﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace XGameFrame.Controls
{
    public class ControlManager:List<Control>
    {

        #region Fields and Properties

        int selectedControl = 0;
        static SpriteFont spriteFont;
        private bool inputDisabledForTime = false;
        private int endTime;
        private bool acceptInput = true;
        private Stopwatch watch;

        public Stopwatch Watch
        {
            get { return watch; }
            set { watch = value; }
        }

        public bool AcceptInput
        {
            get { return acceptInput; }
            set { acceptInput = value; }
        }

        public static SpriteFont SpriteFont
        {
            get { return spriteFont; }
        }

        public bool InputDisabledForTime
        {
            get { return inputDisabledForTime; }
            set { inputDisabledForTime = value; }
        }


        public int EndTime
        {
            get { return endTime; }
            set { endTime = value; }
        }

        #endregion

        #region Event Region

        public event EventHandler FocusChanged;

        #endregion

        #region Constructors

        public ControlManager(SpriteFont pSpriteFont)
            : base()
        {
            ControlManager.spriteFont = pSpriteFont;
        }
        public ControlManager(SpriteFont pSpriteFont, int pCapacity)
            : base(pCapacity)
        {
            ControlManager.spriteFont = pSpriteFont;
        }
        public ControlManager(SpriteFont pSpriteFont, IEnumerable<Control> pCollection) 
            :base(pCollection)
        {
            ControlManager.spriteFont = pSpriteFont;
        }

        #endregion

        #region Methods

        public void Update(GameTime pGameTime, PlayerIndex pPlayerIndex)
        {
            if (Count == 0)
                return;
            if (InputDisabledForTime == true)
            {
                DisableInputForTime();
            }

            foreach (Control c in this)
            {
                
                if (c.Enabled)
                    c.Update(pGameTime);
                if (!AcceptInput)
                    continue;

                c.IsHover = CheckMouseOverControl(c);

                if (c.HasFocus)
                    c.HandleInput(pPlayerIndex);
                if (c.IsHover)
                    c.OnHover(pPlayerIndex);
            }

            if (!AcceptInput)
                return;


            // detects if button up has pushed on the keyboard or pad
            if (InputHandler.ButtonPressed(Buttons.LeftThumbstickUp, pPlayerIndex) ||
                InputHandler.ButtonPressed(Buttons.DPadUp, pPlayerIndex) ||
                InputHandler.KeyPressed(Keys.Up))
                PreviousControl();
            // detects if button down has pushed on the keyboard or pad
            if (InputHandler.ButtonPressed(Buttons.LeftThumbstickDown, pPlayerIndex) ||
                InputHandler.ButtonPressed(Buttons.DPadDown, pPlayerIndex) ||
                InputHandler.KeyPressed(Keys.Down))
                NextControl();

            // detects if the Mouse is over a Control
            if (InputHandler.MouseMove())
                MouseOverControlSelect();

        }

        public void Draw(SpriteBatch pSpriteBatch)
        {
            foreach (Control _c in this)
            {
                if (_c.Visible)
                    _c.Draw(pSpriteBatch);
            }
        }

        public void MouseOverControlSelect()
        {
            if (Count == 0)
                return;

            int currentControl = selectedControl;
            this[selectedControl].HasFocus = false;
            
            int counter = 0;
            foreach (Control _c in this)
            {
                if (CheckMouseOverControl(_c)&&
                    _c.TabStop==true&&
                    _c.Enabled)
                {
                    selectedControl = counter;
                    if (FocusChanged != null)
                        FocusChanged(this[counter], null);
                    break;
                }
                counter++;
            }
            this[selectedControl].HasFocus = true;


        }

        public void NextControl()
        {
            if (Count == 0)
                return;

            int currentControl = selectedControl;
            this[selectedControl].HasFocus = false;

            do
            {
                selectedControl++;
                if (selectedControl == Count)
                    selectedControl = 0;
                if (this[selectedControl].TabStop && this[selectedControl].Enabled)
                {
                    if (FocusChanged != null)
                        FocusChanged(this[selectedControl], null);
                    break;
                }
            } while (currentControl != selectedControl);
            this[selectedControl].HasFocus = true;

        }

        public void PreviousControl()
        {
            if (Count == 0)
                return;
            int currentControl = selectedControl;
            this[selectedControl].HasFocus = false;
            do
            {
                selectedControl--;
                if (selectedControl < 0)
                    selectedControl = Count - 1;
                if (this[selectedControl].TabStop && this[selectedControl].Enabled)
                {
                    if (FocusChanged != null)
                        FocusChanged(this[selectedControl], null);
                    break;
                }
            } while (currentControl != selectedControl);
            this[selectedControl].HasFocus = true;
        }
        /// <summary>
        /// Disable The Input for the ControlManager
        /// </summary>
        /// <param name="pTime">the Seconds how long the ControlManager be disabled</param>
        public void DisableInputForTime(int pTime)
        {
            InputDisabledForTime = true;
            AcceptInput = false;
            EndTime = pTime*1000;
            if (Watch is Stopwatch == false)
                Watch = new Stopwatch();

            Watch.Start();
        }

        protected void DisableInputForTime()
        {
            if (Watch.ElapsedMilliseconds >= EndTime)
                StopDisableInput();
        }

        protected void StopDisableInput()
        {
            AcceptInput = true;
            InputDisabledForTime = false;
            Watch.Reset();
        }

        private Boolean CheckMouseOverControl(Control pC)
        {
            return pC.Bounds.Intersects(new Rectangle(Mouse.GetState().X, Mouse.GetState().Y, 1, 1));
        }

        #endregion


    }
}
